/* Turska UI library
 * Copyright 2003-2008 Jetro Lauha
 * All rights reserved.
 * Web: http://iki.fi/jetro/ or http://jet.ro
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of EITHER:
 *   (1) The GNU Lesser General Public License as published by the Free
 *       Software Foundation; either version 2.1 of the License, or (at
 *       your option) any later version. The text of the GNU Lesser
 *       General Public License is included with this library in the
 *       file LICENSE-LGPL.txt.
 *   (2) The BSD-style license that is included with this library in
 *       the file LICENSE-BSD.txt.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files
 * LICENSE-LGPL.txt and LICENSE-BSD.txt for more details.
 *
 * $Id: UIImageIrr.cpp,v 1.2 2008/03/27 11:44:28 tonic Exp $
 * $Revision: 1.2 $
 */

#include <assert.h>
#include "irrlicht.h"
#include "UI.h"


using namespace irr;


UIImageIrr::UIImageIrr(UIGraphicsIrr *graphics,
                       UINT32 width, UINT32 height, UINT32 flags,
                       irr::video::ITexture *texture, irr::core::vector2df uv[2]) :
    UIImage(width, height, NORMAL, flags),
    mGraphics(graphics),
    mTexture(texture),
    mNegHalfWidth(-0.5f * width),
    mNegHalfHeight(-0.5f * height),
    mPosHalfWidth(0.5f * width),
    mPosHalfHeight(0.5f * height),
    mTargetWidth((FLOAT)width),
    mTargetHeight((FLOAT)height),
    mAngle(0),
    mScaleX(1), mScaleY(1),
    mPivotX(0), mPivotY(0)  // pivot reference point is center of image
{
    assert(graphics);
    mColor.set(0xffffffff);
    mUV[0].set(uv[0]);
    mUV[1].set(uv[1]);
    if (texture)
        texture->grab();
}


UIImageIrr::~UIImageIrr()
{
    if (mTexture)
        mTexture->drop();
}


void UIImageIrr::setColor(UINT8 red, UINT8 green, UINT8 blue, UINT8 alpha)
{
    mColor.set(alpha, red, green, blue);
}


void UIImageIrr::setColor(FLOAT red, FLOAT green, FLOAT blue, FLOAT alpha)
{
    mColor.set((u32)(alpha * 255.f),
               (u32)(red * 255.f),
               (u32)(green * 255.f),
               (u32)(blue * 255.f));
}


void UIImageIrr::draw(UINT drawMode, UINT32 flags, FLOAT x, FLOAT y,
                      FLOAT red, FLOAT green, FLOAT blue, FLOAT alpha)
{
    const FLOAT color[4] = { red, green, blue, alpha };
    video::SColor irrcolor;
    irrcolor.set((u32)(alpha * 255.f),
                 (u32)(red * 255.f),
                 (u32)(green * 255.f),
                 (u32)(blue * 255.f));
    draw(drawMode, flags, x, y, color);
}


void UIImageIrr::draw(UINT drawMode, UINT32 flags, FLOAT x, FLOAT y, const FLOAT *color)
{
    video::SColor irrcolor;
    irrcolor.set((u32)(color[3] * 255.f),
                 (u32)(color[0] * 255.f),
                 (u32)(color[1] * 255.f),
                 (u32)(color[2] * 255.f));
    draw(drawMode, flags, x, y, irrcolor);
}


void UIImageIrr::draw(UINT drawMode, UINT32 flags, FLOAT x, FLOAT y, const irr::video::SColor &color)
{
    // Note: COLOR flag is currently ignored in this implementation.

    video::SMaterial material = mGraphics->getDefaultMaterial();

    if (drawMode != UIImage::NORMAL)
    {
        switch (drawMode)
        {
        case ADD:
            material.MaterialTypeParam = video::pack_texureBlendFunc(video::EBF_SRC_ALPHA, video::EBF_ONE, video::EMFN_MODULATE_1X);
            break;
        case MULTIPLY:
            material.MaterialTypeParam = video::pack_texureBlendFunc(video::EBF_ZERO, video::EBF_SRC_COLOR, video::EMFN_MODULATE_1X);
            break;
        }
    }
    if ((mFlags & WRAP_CLAMP) || (flags & WRAP_CLAMP))
    {
        // setFlag in API is just for bool in Irr 1.4, so we're setting the wrap manually
        //mDefaultMaterial.setFlag(video::EMF_TEXTURE_WRAP, video::ETC_CLAMP_TO_EDGE);
        //for (u32 a = 0; a < video::MATERIAL_MAX_TEXTURES; ++a)
        //    mDefaultMaterial.TextureLayer[a].TextureWrap = video::ETC_CLAMP_TO_EDGE;
        // enough to set just first texture layer as we're using EMT_ONETEXTURE_BLEND
        material.TextureLayer[0].TextureWrap = video::ETC_CLAMP_TO_EDGE;
    }
    if ((mFlags & FILTER_LINEAR) || (flags & FILTER_LINEAR))
        material.setFlag(video::EMF_BILINEAR_FILTER, true);

    material.setTexture(0, mTexture);
    irr::video::IVideoDriver *driver = mGraphics->getIrrDevice()->getVideoDriver();
    driver->setMaterial(material);

    video::S3DVertex vertices[4];
    vertices[0].Color = color;
    vertices[1].Color = color;
    vertices[2].Color = color;
    vertices[3].Color = color;
    vertices[0].TCoords.set(mUV[0].X, mUV[0].Y);
    vertices[1].TCoords.set(mUV[1].X, mUV[0].Y);
    vertices[2].TCoords.set(mUV[0].X, mUV[1].Y);
    vertices[3].TCoords.set(mUV[1].X, mUV[1].Y);

    if (flags & TRANSFORM)
    {
        core::matrix4 transform;

        transform.setTranslation(core::vector3df(x, y, 0));
        if (flags & ROTATE)
            transform.setRotationRadians(core::vector3df(mAngle, 0, 0));
        if (flags & SCALE)
            transform.setScale(core::vector3df(mScaleX, mScaleY, 0));

        if (flags & CENTER)
        {
            vertices[0].Pos.set(mNegHalfWidth - mPivotX, mNegHalfHeight - mPivotY, 0);
            vertices[1].Pos.set(mPosHalfWidth - mPivotX, mNegHalfHeight - mPivotY, 0);
            vertices[2].Pos.set(mNegHalfWidth - mPivotX, mPosHalfHeight - mPivotY, 0);
            vertices[3].Pos.set(mPosHalfWidth - mPivotX, mPosHalfHeight - mPivotY, 0);
        }
        else
        {
            vertices[0].Pos.set(0, 0, 0);
            vertices[1].Pos.set((f32)mWidth, 0, 0);
            vertices[2].Pos.set(0, (f32)mHeight, 0);
            vertices[3].Pos.set((f32)mWidth, (f32)mHeight, 0);
        }
        transform.transformVect(vertices[0].Pos);
        transform.transformVect(vertices[1].Pos);
        transform.transformVect(vertices[2].Pos);
        transform.transformVect(vertices[3].Pos);
    }
    else
    {
        vertices[0].Pos.set(x, y, 0);
        vertices[1].Pos.set(x + mTargetWidth, y, 0);
        vertices[2].Pos.set(x, y + mTargetHeight, 0);
        vertices[3].Pos.set(x + mTargetWidth, y + mTargetHeight, 0);
    }

    u16 indices[6] = { 0, 1, 2,  3, 2, 1 };
    driver->drawVertexPrimitiveList(vertices, 4, indices, 2, video::EVT_STANDARD, scene::EPT_TRIANGLES);
}
